package org.wattdepot.cli;

import org.wattdepot.resource.source.jaxb.SubSources;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.client.WattDepotClientException;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
//import org.wattdepot.client.ResourceNotFoundException;
//import org.wattdepot.client.OverwriteAttemptedException;
//import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.resource.source.jaxb.Source;
import org.wattdepot.resource.sensordata.jaxb.SensorData;
import org.wattdepot.resource.property.jaxb.Property;
import org.wattdepot.resource.property.jaxb.Properties;
import org.wattdepot.util.tstamp.Tstamp;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;

/**
 * Defines methods for extracting data as user requests.
 * @author wattdepot-cli-ewalu group
 *
 */
public class DataExtraction implements ExtractionInterface {
  /** The URL to the public WattDepot Server. */
  private String hostUri = "http://server.wattdepot.org:8182/wattdepot/";
  /** Holds an instance of the WattDepot client. */
  private WattDepotClient client;
  /** Carriage return on this operating system. */
  private String cr = System.getProperty("line.separator");
  /** Constant string to eliminate redundant string literals. */
  public static final String date = "%sT00:00:00.000-10:00";
  /** Constant comparison string to eliminate redundancy. */
  public static final String firstOption = "generated";
  /** Constant comparison string to eliminate redundancy. */
  public static final String secondOption = "consumed";
  
  private List<String> fueltypeList;
  private List<String> sourceNameList;
  
  
  /**
   * Connect to the service and execute some simple commands. Returns immediately if a connection to
   * the service could not be obtained.
   */
  public DataExtraction () {
    client = new WattDepotClient(this.hostUri);
 // Stop right away if we cannot contact server.
    if (!client.isHealthy()) {
      System.out.println("Failed to connect to " + client.getWattDepotUri());
      return;
    }
    // Indicate successful connection.
    System.out.println("Connected to " + client.getWattDepotUri());
  }
  
  /**
   * Returns a string containing a list of all public sources available on this server.
   * 
   * @return A list of sources as a string.
   * @throws WattDepotClientException If problems occur obtaining the list of sources. 
   */
  public String getSourcesInfo() throws WattDepotClientException {
    StringBuffer buff = new StringBuffer(20);
    buff.append("All public sources:").append(cr);
    List<Source> sources = client.getSources();
    for (Source source : sources) {
      buff.append(source.getName()).append(cr);
    }
    return buff.toString();
  }
  
  /**
   * Prints the options with description that can be
   * used for this commandline interface.
   * @return the string consists list of eligible commands
   */
  public String printHelp() {
    String commandList = "";
    commandList = commandList.concat("help\n");
    commandList = commandList.concat("  This message\n");
    commandList = commandList.concat("quit\n");
    commandList = commandList.concat("  Exits the system\n");
    commandList = commandList.concat("sources\n");
    commandList = commandList.concat("  Prints a table summarizing the public" +
      " sources in the system, one per line.\n");
    commandList = commandList.concat("summary {source}\n");
    commandList = commandList.concat("  Prints information about a single source.\n");
    commandList = commandList.concat("sensordata {source} timestamp {timestamp}\n");
    commandList = commandList.concat("  Prints information about a single sensor data " +
      "instance.\n");
    commandList = commandList.concat("dailysensordata {source} day {day}\n");
    commandList = commandList.concat("  Prints a table listing all of the sensor" +
      " data instances for the specified day.\n");
    commandList = commandList.concat("power [generated|consumed] {source} timestamp {timestamp}\n");
    commandList = commandList.concat("  Prints the power generated by the source at " +
      "the given" + " timestamp.\n");
    commandList = commandList.concat("powerstats [generated|consumed] {source} day {day} " + 
      "interval" + " {minutes} statistic {max|min|average}\n");
    commandList = commandList.concat("  Returns the maximum, minimum, or average power" +
      " generated by the source for the day.\n");
    commandList = commandList.concat("total [carbon|energy] [generated|consumed] {source} " +
      "day {day} " + " interval {minutes}\n");
    commandList = commandList.concat("  Returns the total amount of carbon (or energy) " +
      "emitted by this source for the given day.\n");
    commandList = commandList.concat("chart power [generated|consumed] {source} " +
      "{startday} {endday}" + " interval {minutes} file {file}\n");
    commandList = commandList.concat("  Writes out an html file that will display" +
      " a chart illustrating the power for the source over the interval.\n");
    commandList = commandList.concat("fueltypes {source}\n");
    commandList = commandList.concat("  Returns a table of fuels associated with this " +
      "source.\n");
    commandList = commandList.concat("totalpower {source} {timestamp} fueltype {fueltype}\n");
    commandList = commandList.concat("  Returns the total power generated by the given fuel " +
      "type.\n");
    commandList = commandList.concat("carboncontent {source} {timestamp} interval " +
      "{interval}\n");
    commandList = commandList.concat("  Returns the total carbon that would be emitted by " +
      "that source over an hour at the rate occurring as of the timestamp.\n");
    return commandList;
  }
  
  /**
   * Obtain subsources of the desired source.
   * @param plant source of power
   * @return The source's subsources. 
   * @throws WattDepotClientException If problems occur getting the source index. 
   */
  public String getSubSource(String plant) throws WattDepotClientException {
    String summary = "";
    try {
      List<Source> sources = client.getSources();
      for (Source source : sources) {
        if (source.getName().compareTo(plant) == 0 ) {
          String change = source.getSubSources().toString();
          String subsources[] = change.split(",");
          for (int i = 0; i < subsources.length; i++) {
            subsources[i] = subsources[i].substring(52, subsources[i].length());
          } 
          /**String firstOne = "SubSources: " + subsources[0];
          summary = firstOne;*/
          summary = summary.concat(subsources[0]);
          for (int i = 1; i < subsources.length; i++) {
            summary = summary.concat(", " + subsources[i]);
          }
        }
      }
    }
    catch (NullPointerException aNullPointer) {
      summary = "None. ";
    }
    catch (BadXmlException aBadXmlException) {
      System.out.println("WattDepot client receives XML from the server that it " +
        "is unable to unmarshall back into a Java object, or when the server reports " +
        "that the XML it received was bad.");
    }
    catch (MiscClientException aMiscClientException) {
      System.out.println("WattDepot client encounters an unusual error from the server, " +
        "such as an internal server error of some sort. ");
    }
    catch (NotAuthorizedException aNotAuthorizedException) {
      System.out.println("WattDepot client is not authorized to access the requested resource " +
        "(an HTTP 401 status code). ");
    }
    return summary;
  }
  
  /**
   * Obtain description of the desired power source.
   * @param plant power source 
   * @return description of power source
   * @throws WattDepotClientException If problems occur getting the source index. 
   */
  public String getDetail(String plant) throws WattDepotClientException {
    String detail = "\nDescription: ";
    List<Source> sources = client.getSources();
    for (Source source : sources) {
      if (source.getName().compareTo(plant) == 0) {
        detail = detail.concat(source.getDescription());
      }
    }
    return detail;
  }
  
  /**
   * Obtain owner's name of desired power source.
   * @param plant power source 
   * @return owner of power source
   * @throws WattDepotClientException If problems occur getting the source index. 
   */
  public String getPerson(String plant) throws WattDepotClientException {
    String person = "\nOwner: ";
    List<Source> sources = client.getSources();
    for (Source source : sources) {
      if (source.getName().compareTo(plant) == 0) {
        String breakdown[] = source.getOwner().split("/");
        person = person.concat(breakdown[breakdown.length - 1]);
      }
    }
    return person;
  }
  
  /**
   * Obtain location of the desired power source.
   * @param plant power source 
   * @return location of power source
   * @throws WattDepotClientException If problems occur getting the source index.
   */
  public String getPlace(String plant) throws WattDepotClientException {
    String place = "\nLocation: ";
    List<Source> sources = client.getSources();
    for (Source source : sources) {
      if (source.getName().compareTo(plant) == 0) {
        place = place.concat(source.getLocation());
      }
    }
    return place;
  }
  
  /**
   * Obtain coordinates of desired power source.
   * @param plant power source 
   * @return coordinates of power source
   * @throws WattDepotClientException If problems occur getting the source index.
   */
  public String getPlaceCoordinates(String plant) throws WattDepotClientException {
    String coordinates = "\nCoordinates: ";
    List<Source> sources = client.getSources();
    for (Source source : sources) {
      if (source.getName().compareTo(plant) == 0) {
        coordinates = coordinates.concat(source.getCoordinates());
      }
    }
    return coordinates;
  }
  
  /**
   * Obtain property values of desired power source.
   * @param plant power source 
   * @return attribute values of power source
   * @throws WattDepotClientException If problems occur getting the source index.
   */
  public String getAttribute(String plant) throws WattDepotClientException {
    String attributes = "\nProperties: ";
    List<Source> sources = client.getSources();
    try {
      for (Source source : sources) {
        if (source.getName().compareTo(plant) == 0) {
          Properties propertyValues = source.getProperties();
          List<Property> properties = propertyValues.getProperty(); 
          for (Property property : properties) {
            attributes = attributes.concat("(" + property.getKey() +
              " : " + property.getValue() + "), " );
          }
        }
      }
    }
    catch (NullPointerException aNullPointer) {
      attributes = attributes.concat("No property value this moment.  ");
    }
    return attributes;
  }
  
  /**
   * Obtain the data reported from the desired source.
   * @param plant power source 
   * @return time The data of power source
   * @throws WattDepotClientException If problems occur getting the source index.
   */
  public String getData(String plant) throws WattDepotClientException {
    String time = "\nEarliest data: ";
    List<Source> sources = client.getSources();
    for (Source source : sources) {
      if (source.getName().compareTo(plant) == 0) {
        String input = client.getSourceSummary(plant).toString();
        String holder[] = input.split(",");
        for (int i = 1; i < holder.length; i++) {
          if (holder[i].contains("firstSensorData=")) {
            holder[i] = holder[i].replace("firstSensorData=", "");
            time = time.concat(holder[i]);
          }
          else if (holder[i].contains("lastSensorData=")) {
            time = time.concat("\nLatest data: ");
            holder[i] = holder[i].replace("lastSensorData=", "");
            time = time.concat(holder[i]);
          }
          else {
            time = time.concat("\nTotal data points: ");
            holder[i] = holder[i].replace("totalSensorDatas=", "");
            holder[i] = holder[i].replace("]", "");
            time = time.concat(holder[i]);
          }
        }
      }
    }
    return time;
  }
  
  /**
   * Obtain SensorData information regarding desired power source.
   * @param plant The power source
   * @param request The time of the power source.  
   * @return the information of the power source 
   */
  public String getSensorInfo(String plant, XMLGregorianCalendar request) {
    String info = "";
    try {
      List<Source> sources = client.getSources();
      for (Source source : sources) {
        if (source.getName().compareTo(plant) == 0) {
          SensorData data = client.getSensorData(plant, request);
          info = "Tool: " + data.getTool();
          String holder[] = data.getSource().split("/");
          info = info.concat("\nSource: " + holder[holder.length - 1] + "\n");
          Properties subData = data.getProperties();
          List<Property> properties = subData.getProperty();
          info = info.concat("Properties: ");
          for (Property property : properties) {
            info = info.concat("(" + property.getKey());
            info = info.concat(" : ");
            info = info.concat(property.getValue() + ")");
          }
        }
      }
    }
    catch (WattDepotClientException anException) {
      System.out.println("The WattDepot server encounters an error when performing an operation.");
      System.out.println(anException); 
    }
    if (info.equalsIgnoreCase("")) {
      info = info.concat("Check your syntax or type help.");
    }
    return info;
  }
  
  /**
   * Create time requested by client.
   * @param requestTime The time we want to get sensor data from.  
   * @return the time in XMLGregorianCalendar type. 
   * @throws WattDepotClientException If problems occur during operation. 
   */
  public XMLGregorianCalendar getTime(String requestTime) throws WattDepotClientException {
    XMLGregorianCalendar clock = null;
    try {
      clock = Tstamp.makeTimestamp(requestTime);
      if (clock.getDay() > 2009) {
        clock = null;
      }
    }
    catch (Exception e) {
      System.out.println("Check your timestamp syntax.");
    }
    return clock;
  }
  
  /**
   * Obtain power info. as specified by time and source.
   * @param choice generated or consumed
   * @param plant power source
   * @param request specified time
   * @return info that has the power value
   */
  public String getPowerInfo(String choice, String plant, XMLGregorianCalendar request) {
    String info = "";
    try {
      List<Source> sources = client.getSources();
      for (Source source : sources) {
        if (source.getName().compareTo(plant) == 0) {
          if (choice.compareTo(firstOption) == 0) {
            double generation = client.getPowerGenerated(plant, request);
            info = "" + generation;
          }
          else if (choice.compareTo(secondOption) == 0) {
            double consumption = client.getPowerConsumed(plant, request);
            info = "" + consumption;
          }
        }
      }
      if (info.length() == 0) {
        info = "Check your public source and make sure to choose either [generated|consumed].";
      }
    }
    catch (WattDepotClientException anException) {
      System.out.println(anException + "\nThe WattDepot server encounters an error " +
        "when performing an operation.");
    }
    catch (NullPointerException anException) {
      System.out.println("Check your syntax and timestamp format.");
    }
    return info;
  }
  
  /**
   * Obtains the list of sources.
   * @return the list of sources.
   * @throws WattDepotClientException If problems occur during operation.
   */
  public StringBuffer listSources() throws WattDepotClientException {
    StringBuffer result = new StringBuffer();
    
    List<Source> sources = client.getSources();
    int listLength = sources.size();
    System.out.println("Name\t\tParent\t\t\tDescription\n");
    for (int i = 0; i < listLength; i++) {

      String sourceName = sources.get(i).getName();
      String parentName = "";
      boolean parentFound = false;
      
      for (int j = 0; j < sources.size(); j++) {
        String subSources = "";
        if (sources.get(j).isSetSubSources()) {
          subSources = (sources.get(j)).getSubSources().toString();
          String splitSubSources[] = subSources.split(",");
          
          for (int k = 0; k < splitSubSources.length; k++) {
            String splitSubSourceNames[] = splitSubSources[k].split("[\\[/\\]]");
            String subSourceName = splitSubSourceNames[splitSubSourceNames.length - 1];
            if (sourceName.compareTo(subSourceName) == 0) {
              parentName = sources.get(j).getName();
              parentFound = true;
            }
          }
       
        }
        
      }
      if (parentFound) {
        result.append(sourceName + "\t\t" + parentName
            + "\t\t" + sources.get(i).getDescription() + "\n");
      }
      else {
        result.append(sources.get(i).getName() + "\t\t\t" + sources.get(i).getDescription()
            + "\n");
      }
    }
    return result;
  }
  
  /**
   * Lists the sensor data of the specific date. 
   * 
   * @param sourceName is the name of the source.
   * @param day specifies the day to look for.
   * @throws WattDepotClientException If anything goes wrong.
   * @return a list of sensor data.
   */
  public StringBuffer listSensorDataByDate(String sourceName, String day) 
    throws WattDepotClientException {
    StringBuffer result = new StringBuffer(1000);

    XMLGregorianCalendar formattedStampStart = null, formattedStampEnd = null;
    String timestampStart = day + "T00:00:00.000-10:00";
    String timestampEnd = day + "T23:59:59.000-10:00";
 
    if (Tstamp.isTimestamp(timestampStart) && Tstamp.isTimestamp(timestampEnd)) {
      formattedStampStart = this.getTime(timestampStart);
      formattedStampEnd = this.getTime(timestampEnd);
         List<SensorData> sensorDatas = client.getSensorDatas(sourceName, formattedStampStart,
          formattedStampEnd);
  
      for (int i = 0; i < sensorDatas.size(); i++) {
        String timestamp = sensorDatas.get(i).getTimestamp().toString();
        String tool = sensorDatas.get(i).getTool();
        String property = sensorDatas.get(i).getProperties().toString();
        
        result.append(timestamp + "  Tool:  " + tool + "  Properties:  " + property + "\n");
      }
      if (result.length() == 0) {
        result.append("No data. Check your parameters, i.e, timestamp.");
      }
      return result;
    }
    else {
      return null;
    }
  }
  
  /**
   * 
   * @param option defines the option available for this method.
   * @param sourceName is the name of the source instance.
   * @param day is the date input.
   * @param intervalStr is the string representation of the interval.
   * @param statistic defines what the type of output.
   * @return either max, min, or average value of the output.
   * @throws WattDepotClientException If something goes wrong.
   */
  public String listPower(String option, String sourceName, String day, String intervalStr,
      String statistic) throws WattDepotClientException {
    String result = "";
    Integer interval = Integer.parseInt(intervalStr);
    if (interval > 0) {
      List<Double> powerList = new ArrayList<Double>();
      String formattedStartTime = String.format(date, day);
      if (Tstamp.isTimestamp(formattedStartTime)) {
        XMLGregorianCalendar startTimestamp = this.getTime(formattedStartTime);
        XMLGregorianCalendar endTimestamp = startTimestamp;
        endTimestamp = Tstamp.incrementDays(endTimestamp, 1);
        
        while (!startTimestamp.equals(endTimestamp)) {
          if (option.compareTo(firstOption) == 0) {
            powerList.add(client.getPowerGenerated(sourceName, startTimestamp));
          }
          else if (option.compareTo(secondOption) == 0) {
            powerList.add(client.getPowerConsumed(sourceName, startTimestamp));
          }
          else {
            return result = "Choose either generated or consumed.";
          }
          startTimestamp = Tstamp.incrementMinutes(startTimestamp, interval);
        }
      }
    
      if (!powerList.isEmpty()) {
        if (statistic.compareTo("max") == 0) {
          result = "" + getMax(powerList);
        }
        else if (statistic.compareTo("min") == 0) {
          result = "" + getMin(powerList);
        }
        else if (statistic.compareTo("average") == 0) {
          result = "" + getAverage(powerList);
        }
        else {
          result = "Type exactly either max, min, or average.";
        }
      }
    }
    else {
      result = "Check your interval is not negative or zeros.";
    }
    return result;
  }
  
  /**
   * Returns the largest value in the List.
   * @param list is the List of Double.
   * @return returns the largest element within the list.
   */
  public Double getMax(List<Double> list) {
    Double max = list.get(0);
    for (int i = 1; i < list.size(); i++) {
      if (list.get(i) > max) {
        max = list.get(i);
      }
    }
    return max;
  }
  
  /**
   * Returns the smallest value in the List.
   * @param list is the List of Double.
   * @return returns the smallest element within the list.
   */
  public Double getMin(List<Double> list) {
    Double min = list.get(0);
    for (int i = 1; i < list.size(); i++) {
      if (list.get(i) < min) {
        min = list.get(i);
      }
    }
    return min;
  }
  
  /**
   * Calculates the average value of all the list values.
   * @param list is the List of Double.
   * @return returns the average value of the elements in the list.
   */
  public Double getAverage(List<Double> list) {
    Double total = 0.0;
    for (int i = 0; i < list.size(); i++) {
      total += list.get(i);
    }
    return total / list.size();
  }
  
  
  /**
   * Gets the total amount of carbon or energy emitted.
   * 
   * @param option defines whether to return carbon emission or energy consumption.
   * @param choice generated or consumed in energy.
   * @param sourceName is the name of the source.
   * @param day is the date input.
   * @param intervalStr is the sampling interval in String format.
   * @return returns the total carbon emissions or energy consumption within a day.
   * @throws WattDepotClientException If anything goes wrong.
   */
  public String listTotal(String option, String choice, String sourceName, 
    String day, String intervalStr) throws WattDepotClientException {
    String result = "";
    
    Integer interval = Integer.parseInt(intervalStr);
    if (interval > 0) {
      String startTimestamp = String.format(date, day);
      String endTimestamp = String.format("%sT23:59:00.000-10:00", day);
   
      if (Tstamp.isTimestamp(startTimestamp) && Tstamp.isTimestamp(endTimestamp)) {
        XMLGregorianCalendar formattedStartTimestamp = this.getTime(startTimestamp);
        XMLGregorianCalendar formattedEndTimestamp = this.getTime(endTimestamp);
        if ((option.compareTo("carbon") == 0) &&
          (choice.compareTo(firstOption) == 0 || 
           choice.compareTo(secondOption) == 0)) {
          Double carbonEmitted = client.getCarbonEmitted(sourceName, formattedStartTimestamp,
          formattedEndTimestamp, interval);
          result = "" + carbonEmitted;

        }
        else if (option.compareTo("energy") == 0) {
          if (choice.compareTo(firstOption) == 0) {
            Double energyGenerated = client.getEnergyGenerated(sourceName, formattedStartTimestamp, 
            formattedEndTimestamp, interval);
            result = "" + energyGenerated;
          }
          else if (choice.compareTo(secondOption) == 0) {
            Double energyConsumed = client.getEnergyConsumed(sourceName, formattedStartTimestamp, 
            formattedEndTimestamp, interval);
            result = "" + energyConsumed;
          }
          else {
            result = "Type exactly either [generated|consumed].";
          }
        }
        else {
          result = "Specify either exactly [carbon|energy] [generated|consumed]";
        }
      }
      else {
        result = "Check your timestamp syntax.";
      }
    }
    else {
      result = "Check your interval is not negative or zeros.";
    }
    return result;
  }
  
  /**
   * Charts the power data.
   * 
   * @param option defines whether to chart power or energy generated.
   * @param sourceName is the name of the source instance.
   * @param startDay is the beginning date.
   * @param endDay is the end date.
   * @param intervalStr is the interval value in String format.
   * @param filename is the name of the file to output to.
   * @return returns the current directory and the output filename upon success.
   * @throws IOException if anything goes wrong. 
   * @throws WattDepotClientException If anything goes wrong.
   */
  public String chartPower(String option, String sourceName, String startDay, String endDay, 
      String intervalStr, String filename) throws WattDepotClientException, IOException {
    Integer interval = Integer.parseInt(intervalStr);
   
    List<Double> powerList = new ArrayList<Double>();
    
    String splitStartDay[] = startDay.split("-");
    if (splitStartDay.length != 3) {
      return "Error in format startDate";
    }
    String startDate = String.format(date, startDay);
    String endDate = String.format(date, endDay);
    if (Tstamp.isTimestamp(endDate) && Tstamp.isTimestamp(startDate)) {
      XMLGregorianCalendar formattedStartDate = this.getTime(startDate);
      XMLGregorianCalendar formattedEndDate = this.getTime(endDate);
    
      while (!formattedStartDate.equals(formattedEndDate)) {
      
        powerList.add(client.getPowerGenerated(sourceName, formattedStartDate) / 10000000);
        formattedStartDate = Tstamp.incrementMinutes(formattedStartDate, interval);
      }
      BufferedWriter out = new BufferedWriter(new FileWriter(filename));

      out.write("<html><body><img src=http://chart.apis.google.com/" + 
      "chart?chs=250x100&cht=lc&chd=t:");
      for (int i = 0; i < powerList.size(); i++) {
        String toOutput = "";
        if (i == 0) {
          toOutput = "" + powerList.get(i);
        }
        else {
          toOutput = "," + powerList.get(i);
        }
        out.write(toOutput);
      }
      out.write("></body></html>");
      out.close();
    }
    return "Wrote:  " + System.getProperty("user.dir") + "/" + filename;
  }


  
  /**
   * Checks for the subsources of the input source and returns a list
   * of sources grouped by fuel type.
   * @param sourceName the desired source
   * @return a list of sources grouped by fuel type.
   * @throws WattDepotClientException If info cannot be retrieved.
   */
  public StringBuffer getFueltype(String sourceName) throws WattDepotClientException {
     String fuelType = "";
     Source sourceMatched = null;
     List<Source> sources = client.getSources();
     for (Source source : sources) {
       if (source.getName().compareTo(sourceName) == 0) {
         sourceMatched = source;
       }
     }

     fueltypeList = new ArrayList<String>();
     sourceNameList = new ArrayList<String>();
     traverseSubSources(sourceMatched);
     
     StringBuffer buff = new StringBuffer(1000);
     List<String> done = new ArrayList<String>();

     for (int i = 0; i < fueltypeList.size(); i++) {
       boolean found = false;
       for (int j = 0; j < done.size(); j++) {
         if (fueltypeList.get(i).compareTo(done.get(j)) == 0) {
           found = true;
         }
       }
       if (!found) {
         String type = fueltypeList.get(i);
         done.add(type);
         String toAppend = type + " : " + sourceNameList.get(i);
         buff.append(toAppend);
         for (int j = i + 1; j < fueltypeList.size(); j++) {
           if (type.compareTo(fueltypeList.get(j)) == 0) {
           toAppend = "," + sourceNameList.get(j);
           buff.append(toAppend);
           }
         }
         toAppend = "\n";
         buff.append(toAppend);
       }
     }
     return buff;
  }
  
  /**
   * Traverses the subsources until it finds a node with a property.
   * @param source the desired source
   * @throws WattDepotClientException If info cannot be retrieved.
   */
  public void traverseSubSources(Source source) throws WattDepotClientException  {

     if (source.isSetProperties()) {
       fueltypeList.add(source.getProperty("fuelType").toString());
       sourceNameList.add(source.getName());
       return;
     }

     SubSources subs = null;
     if (source.isSetSubSources()) {
       subs = source.getSubSources();
       List<String> listOfSubsources = subs.getHref();
       for (int i = 0; i < listOfSubsources.size(); i++) {
         String href[] = listOfSubsources.get(i).split("/");
         traverseSubSources(client.getSource(href[href.length - 1])); 
       }
     }
  }


  /**
   * Give the total power associated with the fuel type and source.
   * @param input the desired source
   * @param plant is the desired public source
   * @param request is the time to retrieve info.
   * @param fuelType is the type of fuel of source
   * @return a string that displays the total power
   * @throws WattDepotClientException If info cannot be retrieved.
   */
  public String totalPower(String input, String plant, XMLGregorianCalendar request
    , String fuelType) throws WattDepotClientException {
    String output = "";
    double count = 0;
    String subSourceList = plant.substring(0, plant.length() - 1);
    List<Source> sources = client.getSources();
    String tempHolder[] = subSourceList.split(", ");
    if (subSourceList.contains("None")) {
      for (Source source : sources) {
        if ((source.getName().compareTo(input) == 0) &&
          (source.getProperty("fuelType").equals(fuelType))) {
          SensorData property = client.getSensorData(input, request);
          count = property.getPropertyAsDouble("powerGenerated"); 
        }
      }
      if (output.length() == 0) {
        output = "There is no non-virtual source with specified fuel type.";
      }
    }
    else {
      for (String subSource : tempHolder) {
        for (Source source : sources) {
          if ((source.getName().compareTo(input) == 0) &&
            (source.getProperty("fuelType").equals(fuelType))) {
            output = fuelType;
            SensorData property = client.getSensorData(subSource, request);
            count += property.getPropertyAsDouble("powerGenerated");
          }
        }
      }
    }
    if (output.length() == 0) {
      output = "Tip#1: Type summary {source} for fuel type.";
    }
    if (count != 0) {
      count = count / 1000000;
    }
    output = "The total power generated from " + fuelType +
      " = " + count + " MW";
    return output;
  }

  /**
   * Returns the calculated value of carbon content.
   * @param sourceName the desired source
   * @param timestamp is the desired timestamp input.
   * @param interval is the desired interval to calculate the result with.
   * @return a value of the calculated carbon content value.
   * @throws WattDepotClientException If info cannot be retrieved.
   */
  public String getCarboncontent(String sourceName, String timestamp, String interval)
  throws WattDepotClientException {
    Source sourceMatched = null;
    List<Source> sources = client.getSources();
    for (Source source : sources) {
      if (source.getName().compareTo(sourceName) == 0) {
        sourceMatched = source;
      }
    }
    
    if (Tstamp.isTimestamp(timestamp)) {
      XMLGregorianCalendar startTimestamp = this.getTime(timestamp);
      XMLGregorianCalendar endTimestamp = Tstamp.incrementMinutes(startTimestamp, 60);
      Integer intervalInt = Integer.parseInt(interval);
      Double carbonEmitted = client.getCarbonEmitted(sourceName, startTimestamp,
      endTimestamp, intervalInt);
      Double energyGenerated = client.getEnergyGenerated(sourceName, startTimestamp,
      endTimestamp, intervalInt);

      Double result = (carbonEmitted / energyGenerated) * 1000000;
      return result + " lbs CO2/MWh";
    }
    return null;
  }
}
